<template>
  <div class="gantt-panel"
       :class="{'hide-gantt-box': hideGantt}"
       :style="{width: ganttWidth}">
    <div v-show="ganttReady"
         class="hide-gantt-btn"
         :class="{'hide-gantt-btn-close': hideGantt}"
         @click="setHideGantt()"></div>
    <div class="scale-unit" v-if="hasScaleUnit">
      <div class="scale-unit-active-box"
           @click="handlerScaleUnitClick">
        {{scaleUnitActive.label}}
        <i class="scale-unit-icon CAP cap-icon-arrow-down"></i>
      </div>
      <div class="scale-unit-box"
           v-show="scaleUnitShow">
        <div class="scale-unit-item"
             :class="{'scale-unit-item-active': item.value === scaleUnitActive.value}"
             v-for="(item, index) in scaleUnit"
             :key="index"
             @click="handlerScaleUnitSelect(item)">{{item.label}}</div>
      </div>
    </div>
    <div class="gantt-box"
         ref="gantt"
         :style="{height: this.height + 'px'}"></div>
  </div>
</template>
 
<script>
import { gantt } from 'dhtmlx-gantt';
import Bus from './../bus'
export default {
  name: 'gantt',
  props: {
    ganttCanOpa: {
      type: Boolean,
      default: false
    },
    width: {
      type: [String, Number],
      default: '50%'
    },
    height: {
      type: [String, Number],
      default: '400px'
    },
    show: {
      type: Boolean,
      default: true
    },
    unit: {
      type: String,
      default: 'day'
    },
    affiliationBox: {
      type: String,
      default: 'table-class'
    },
    contentBox: {
      type: String,
      default: 'el-table__body-wrapper'
    },
    dataLength: {
      type: [String, Number],
      default: 7
    },
    config: {
      type: Object,
      default: () => {
        return {
          scale_height: 46,
          task_height: 36,
          row_height: 36
        }
      }
    },
    formId: {
      type: [String, Number],
      default: ''
    },
    defaultData: {
      type: Array,
      default: () => {
        return []
      }
    },
    defaultScroll: {
      type: Object,
      default: () => {
        return {
          x: 0,
          y: 0
        }
      }
    }
  },
  data () {
    return {
      ganttWidth: '100%',
      ganttReady: false,
      hideGantt: false,
      scaleUnitShow: false,
      hasScaleUnit: false,
      currtX: 0,
      currtY: 0,
      scaleUnit: [
        { label: '日视图', value: 'day', active: false },
        { label: '周视图', value: 'week', active: true },
        { label: '月视图', value: 'month', active: false }
      ],
      scaleUnitActive: { label: '日视图', value: 'day' },
      ganttHeight: '0px',
      rectGantt: {
        x: '0',
        y: '173px'
      },
      tasks: {
        data: [],
        links: [

        ]
      },
      linksIdNumber: 0,
      fieldKey: [],
      eventList: [],
      oldProgress: 0,
      openRowId: [],
      superId: ''
    }
  },
  created() {
    
    // gantt.detachEvents();
    //gantt.clearAll();
  },
  beforeDestroy () {
    //detachEvents
    for (var i=0; i < this.eventList.length; i++) {
      gantt.detachEvent(this.eventList[i]); 
    }
    this.eventList = [];
  },
  mounted () {
    let that = this;
    //this.getFieldKey();
    //this.setTaskData();
    this.getGanttHeight();
    this.initGantt();
  },
  methods: {
    setHideGantt () {
      this.hideGantt = !this.hideGantt
    },
    getGanttHeight () {
      // let contentClass = this.contentBox || 'v-easy-table-body';
      //let ganttHeight = document.getElementsByClassName(contentClass)[0].offsetHeight + 49; //加一行40px-scale高度及8px-滚动条占用高度
      //
      this.ganttHeight = this.height + 'px';
    },
    setTaskData (data) {
      let today = new Date(),
          datas = data || this.defaultData;
      //初始化
      this.tasks = { data: [], links: [] };
      for (let item of datas) {
        let dataJson = {}, linksJson = {};
        //计算时间
        //let time = this.setTimeParam(item[fieldKey.startTime]);
        dataJson.id = item.taskId;
        dataJson.text = item.title || '';
        dataJson.person = item.manager || '';
        dataJson.start_date = item.startDate ? item.startDate + ' 00:00:01' : today;
        dataJson.end_date = item.endTime ? item.endTime + ' 23:59:59' : today;
        dataJson.folder = item.folder;

        if(typeof dataJson.start_date === 'string') {
          dataJson.start_date = dataJson.start_date.split('-').join('/');
        }

        if(typeof dataJson.end_date === 'string') {
          dataJson.end_date = dataJson.end_date.split('-').join('/');
        }

        dataJson["$has_child"] = !!item.hasChildren;
        dataJson['folder'] = !!item.folder;
        //dataJson.duration = time.duration;
        if (!!item.superId) {
          dataJson.parent = item.superId;
        }
        if(!!this.superId) {
          dataJson.parent = this.superId;
        }

        dataJson.progress = parseFloat(item.processRateNum || '0');
        dataJson.open = !!item.fold;
        if (!!item.frontTaskId) {
          linksJson.id = this.linksIdNumber++;
          linksJson.source = item.frontTaskId;
          linksJson.target = item.taskId;
          linksJson.type = '0';
          this.tasks.links.push(linksJson);
        }
        this.tasks.data.push(dataJson);}
      return this.tasks;
    },
    initGantt () {
      let that = this;
      //配置数据
      this.setTaskData();

      gantt.i18n.setLocale('cn');
      gantt.plugins({
        marker: true,
        tooltip: true
      });

      //
      this.setGanttConfig();
      this.setGanttTemplate();
      this.setGanttEvent();

      //今日竖线
      this.drawToday();

      gantt.init(this.$refs.gantt);
      gantt.parse(this.tasks);
      // this.$nextTick(() => {
      //   this.ganttReady = true;
      //   if (!!this.defaultScroll.y) {
      //     this.ganttScrollTo(0, this.defaultScroll.y);
      //   }
      // })
    },
    drawToday () {
      let date_to_str = gantt.date.date_to_str(gantt.config.task_date);

      gantt.addMarker({
        start_date: new Date(),
        css: "today",
        text: "今日",
        title: "今日: " + date_to_str(new Date())
      });
    },
    setGanttConfig () {
      //开启懒加载
      gantt.config.branch_loading = true;
      gantt.config.columns = [
        // {name: "staff", label: "", align: "right", width: 50, template: function(obj) {
        //     return (obj.hasChildren) ? '<div class="gantt-dync-plus" data-id="' + obj.id + '" onclick="ganttLoad(this)">＋</div>' : '';
        // }},
        {name: "staff", label: "任务标题", tree: true, align: "left", width: 500, template: function(obj) {
            return `<span>${obj.text}</span>`;
        }}
      ];
      gantt.config.scale_height = this.config.scale_height;
      gantt.config.task_height = this.config.task_height;
      gantt.config.row_height = this.config.row_height;

      //gantt.config.work_time = true;
      gantt.config.drag_links = true;
      gantt.config.show_grid = true;
      gantt.config.task_date = '%Y年%m月%d';
      
      gantt.config.round_dnd_dates = false;
      this.changeConfigScaleUnit();
    },
    setGanttTemplate () {
      let dateToStr = gantt.date.date_to_str("%Y-%m-%d %H:%i:%s");

      gantt.templates.rightside_text = function (start, end, task) {
        return task.folder ? '' : '<p style="float: left; color: #333;">' + (task.progress * 100).toFixed(2) + '%</p>';
      };
      gantt.templates.parse_date = function(date){
        const type = Object.prototype.toString.call(date)
          if(type === '[object String]') {
            date = new Date(date);
          } else if(type === '[object Date]') {
            date = date;
          } else {
            return new Date();
          }
          return date;
      };
      // gantt.templates.format_date = function(date){
      //     return dateToStr (date);
      // };
      gantt.templates.task_text = function (start, end, task) {
        return '';
      };
      gantt.templates.task_class = function (start, end, item) {
        let taskClass = 'gantt_task_in_progress';

        if (item.end_date < new Date()) {
          taskClass += ' gantt_task_outtime';
        }

        if (item.progress === 1) {
          taskClass = 'gantt_task_in_complete';
        }
        return taskClass
      };
      gantt.templates.tooltip_text = function (start, end, task) {
        return "<div class='gantt-tooltip-box'><span style='color:#000'>任务名称:</span> <span style='color:#666'>" + task.text + "</span>" +
          "<br/><span style='color:#000'>开始时间:</span> <span style='color:#666'> " + dateToStr(start) + "</span>" +
          "<br/><span style='color:#000'>结束时间:</span> <span style='color:#666'> " + dateToStr(end) + "</span>" + "</div>";
      };
      gantt.templates.scale_cell_class = function (date) {
        let today = new Date();
        if (date.getDay() == today.getDay() && date.getMonth() == today.getMonth() && date.getFullYear() == today.getFullYear()) {
          return "today";
        }
      };
      gantt.templates.timeline_cell_class = (task, date) => {
        if (this.scaleUnitActive.value === 'day' && (date.getDay() == 0 || date.getDay() == 6)) {
          return "weekend";
        }
      };
      gantt.templates.link_class = function (link) {
        return "gantt-links-color";
      };
    },
    expandAll() {
      for (const i of this.openRowId) {
        this.ganttOpen(i)
      }
    },
    collapseAll() {
      for (const i of this.openRowId) {
        this.ganttClose(i)
      }
    },
    setGanttEvent () {
      let that = this;
      let date_to_str = gantt.date.date_to_str('%Y-%m-%d %H:%i:%s');

      let openEvent = gantt.attachEvent("onTaskOpened", function(id) {
          const task = gantt.getTask(id);
          that.superId = id;
          const sPos = gantt.getScrollState();
          //any custom logic here
          Bus.$emit('getTableList', {resolve: function(arr) {
              let childTaskList = that.setTaskData(arr);
              
              gantt.parse(childTaskList);
              if (that.openRowId.indexOf(id) < 0) {
                that.openRowId.push(id);
              }
              that.superId = '';
              that.ganttScrollTo(sPos.x, sPos.y);
            }, isLoad: true, taskId: id, folder: task.folder});
      });
      this.eventList.push(openEvent);

      //禁止双击修改
      gantt.attachEvent("onTaskDblClick", function (id, e) {
        return false;
      });
      //禁止双击删除
      gantt.attachEvent("onLinkDblClick", function (id, e) {
        return that.ganttCanOpa;
      });
      //任务拖动
      let dragEvent1 = gantt.attachEvent("onBeforeTaskDrag", function (id, mode, e) {
        const task = gantt.getTask(id);
        that.oldProgress =  task.progress;
        return (mode === 'progress') && !task.folder && that.ganttCanOpa;
      });
      this.eventList.push(dragEvent1);
      //任务拖动
      let dragEvent = gantt.attachEvent("onAfterTaskDrag", function (id, mode, e) {
        //TODO
        let task = gantt.getTask(id);
        //根据拓展，计算任务当前进度的时间
        let progressData = new Date(task.start_date).getTime() + (task.duration * 60 * 60 * 24 * 1000 * task.progress) * 1;

        //构造接口参数
        let params = {};
        params['taskId'] = id;
        switch (mode) {
          case 'progress':
            params['processRate'] = task.progress.toFixed(4) * 100;
            //触发事件
            const msg = '拖动进度后，任务进度将不再自动计算，是否修改？'
            that.$confirm(msg, '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
              Bus.$emit('handlerTaskUpdate', params);
            }).catch(res => {
                that.setTaskProcess(id, that.oldProgress);
            });
            break;
          case 'resize':
          case 'move':
            params['updateStartTime'] = date_to_str(task.start_date);
            params['updateEndTime'] = date_to_str(task.end_date);
            //触发事件
            that.$emit('handlerTaskUpdate', { params: params, task: task });
            break;
          default: break;
        }
      });
      this.eventList.push(dragEvent);

      //任务修改
      gantt.attachEvent("onAfterTaskUpdate", function (id, item) {
        //TODO
        //that.$emit('handlerTaskUpdate', { id, item });
      });
      //任务选中
      let rowClickEvent = gantt.attachEvent("onTaskRowClick", function(id, row) {
          const task = gantt.getTask(id);
          if(!task.folder) {
            if(!row.getAttribute("class") || row.getAttribute("class").indexOf('gantt_tree_icon') < 0) {
              Bus.$emit('viewTableList', { taskId: task.id, superId: task.parent });
            }
          }
          
      });
      this.eventList.push(rowClickEvent);
      //任务houver
      gantt.attachEvent("onAfterTaskMove", function (id, parentId, tindex) {
        //TODO
      });
      //关系添加
      gantt.attachEvent("onBeforeLinkAdd", function (id, item) {
        //TODO
        const targetTask = gantt.getTask(item.target);
        const sourceTask = gantt.getTask(item.source);
        if (targetTask.folder || sourceTask.folder || !that.ganttCanOpa) {
          return false;
        }
        return true;
        
      });
      let addFrontEvent = gantt.attachEvent("onAfterLinkAdd", function (id, item) {
        //TODO
        Bus.$emit('modifyFrontTask', {id: id, target: item.target, source: item.source});
      });
      this.eventList.push(addFrontEvent);
      //关系删除
      let delrontEvent = gantt.attachEvent("onAfterLinkDelete", function (id, item) {
        //TODO
        Bus.$emit('modifyFrontTask', {target: item.target, source: null});
      });
      this.eventList.push(delrontEvent);
      //滚动条滚动
      gantt.attachEvent("onGanttScroll", function (x1, y1, x2, y2) {
        //TODO
        that.currtX = x2;
        that.currtY = y2;
        //that.$emit('handlerGanttScroll', { x: x2, y: y2 });
      });
    },

    //外部API
    ganttScrollTo (x, y) {
      gantt.scrollTo(x, y);
    },
    getSelectionTaskId() {
      return gantt.getSelectedId();
    },
    setTaskProcess (id, val) {
      gantt.getTask(id).progress = val || this.oldProgress; //changes task's data
      gantt.updateTask(id);
    },
    ganttClose (id) {
      gantt.close(id);
    },
    ganttOpen (id) {
      gantt.open(id);
    },
    ganttRender () {
      gantt.render();
    },
    ganttChangeView(data) {
      this.handlerScaleUnitSelect(data);
    },
    delTaskLinkId(id) {
      gantt.deleteLink(id);
    },
    //重新加载数据
    reloadData (data) {
      //配置数据
      this.setTaskData();
      gantt.clearAll();
      this.drawToday();
      gantt.parse(this.tasks);
    },
    changeConfigScaleUnit () {
      switch (this.scaleUnitActive.value) {
        case 'day':
          gantt.config.scale_unit = "month";
          gantt.config.xml_date = "%Y-%m-%d";
          gantt.config.date_scale = "%Y年%M";
          gantt.config.subscales = [
            { unit: "day", step: 1, date: "%j" }
          ];
          break;
        case 'week':
          gantt.config.scale_unit = "month";
          gantt.config.xml_date = "%Y-%m-%d";
          gantt.config.date_scale = "%Y年%M";
          gantt.config.subscales = [
            //{unit: "week", step: 1, date: "%j"}
            {
              unit: "week", step: 1, template: function (date) {
                return Math.ceil((date.getDate() + 6 - date.getDay()) / 7);
              }
            },
          ];
          break;
        case 'month':
          gantt.config.scale_unit = "year";
          gantt.config.xml_date = "%Y-%m-%d";
          gantt.config.date_scale = "%Y年";
          gantt.config.subscales = [
            { unit: "month", step: 1, date: "%n" }
          ];
          break;
        default: break;
      }
    },
    changeConfig (obj) {
      Object.assign(gantt.config, obj, true);
    },

    handlerScaleUnitClick () {
      this.scaleUnitShow = !this.scaleUnitShow;
    },

    handlerScaleUnitSelect (data) {
      this.scaleUnitActive = data;
      this.scaleUnitShow = false;
      //修改日月周视图
      this.changeConfigScaleUnit();
      this.ganttRender();
    }
  },
  watch: {
    defaultData: {
      handler: function (val) {
          this.reloadData();
      },
      deep: true
    },
  },
}
</script>
 
 <style lang="scss">
$links-color: rgba(255, 0, 0, 1);
$task-default-color: #d4e7fb;
$task-progress-color: #1f85ec;
$task-complete-color: #67c13a;
$task-outtime-color: #f56c6c;
$task-hover: #666;
.hide-gantt-btn {
  display: none;
  position: absolute;
  top: 0;
  left: -20px;
  background: #fff;
  opacity: 0.8;
  width: 20px;
  height: 20px;
  line-height: 20px;
  z-index: 18;
  cursor: pointer;
  border-style: solid;
  border-width: 1px 0 1px 1px;
  border-color: #e4e7ed;
  border-radius: 2px;
}
.hide-gantt-btn::after {
  content: "\25BA";
  color: #333;
  position: relative;
  z-index: 19;
  display: block;
  width: 14px;
  margin: auto;
}
.hide-gantt-btn-close::after {
  content: "\25C4";
}
.hide-gantt-box {
  left: 100% !important;
}
.gantt-panel {
  position: relative;
  width: 50%;
}
/*links颜色配置*/
.gantt_line_wrapper div {
  background-color: $links-color !important;
}
.gantt_link_arrow_right {
  border-left-color: $links-color !important;
}
.gantt_task_outtime {
  border: solid 1px $task-outtime-color !important;
}
.gantt_task_in_default .gantt_task_progress {
  background-color: $task-default-color;
}
.gantt_task_in_progress .gantt_task_progress {
  background-color: $task-progress-color;
}
.gantt_task_in_complete .gantt_task_progress {
  background-color: $task-complete-color;
  border-radius: 12px;
}
.gantt_task_outtime .gantt_task_progress {
  background-color: $task-outtime-color;
}
.gantt_task_line.gantt_selected {
  box-shadow: 0 0 5px $task-hover !important;
}
.gantt_task_outtime.gantt_selected {
  box-shadow: 0 0 5px $task-outtime-color !important;
}
</style>
<style>
@import "~dhtmlx-gantt/codebase/dhtmlxgantt.css";
.gantt_task .gantt_task_scale .gantt_scale_cell{
  border-right: 1px solid #e4e7ed;
}
.gantt_layout_cell_border_bottom {
  border-bottom: 1px solid #e4e7ed;
}
.gantt_layout_cell_border_top {
  border-top: 1px solid #e4e7ed;
}
.gantt_layout_cell_border_right {
  border-right: 1px solid #e4e7ed;
}
.gantt_layout_cell_border_left {
  border-left: 1px solid #e4e7ed;
}
.gantt_scale_line {
  border-top: 1px solid #e4e7ed;
}
.gantt_grid_scale, .gantt_task_scale {
  border-bottom: 1px solid #e4e7ed;
}
.gantt_link_control {
  top: -10px;
}
.scale-unit {
  position: absolute;
  right: 0;
  top: 0;
  width: 128px;
  height: 45px;
  font-size: 14px;
  z-index: 1;
  border: 1px solid #e4e7ed;
  background-color: #fff;
  color: #333333;
  cursor: pointer;
}
.scale-unit .scale-unit-icon {
  position: absolute;
  right: 10px;
  font-size: 14px;
  z-index: 2;
}
.scale-unit .scale-unit-active-box {
  width: 120px;
  height: 46px;
  text-align: center;
  line-height: 40px;
}
.scale-unit .scale-unit-box {
  background-color: #fff;
  border-width: 1px;
  border-style: solid;
  border-color: #e4e7ed;
}
.scale-unit .scale-unit-box .scale-unit-item {
  text-align: center;
  line-height: 40px;
  width: 120px;
  height: 40px;
  color: #999;
}
.scale-unit .scale-unit-box .scale-unit-item-active {
  color: #333;
}
.gantt-box {
  width: 100%;
  height: auto;
}

.weekend {
  background-color: #fafafa;
}
.gantt_selected .weekend {
  background-color: #fafafa;
}
.gantt-tooltip-box {
  line-height: 24px !important;
}
.gantt_task_line {
  border: none;
  background-color: #d4e7fb;
  border-radius: 12px;
  height: 16px !important;
  line-height: 16px !important;
  margin-top: 8px !important;
  box-sizing: border-box;
}
.gantt-dync-plus{
  cursor: pointer;
  border: 1px solid #454545;
  display: inline-block;
  text-align: center;
  font-size: 12px;
  height: 12px;
  line-height: 12px;
  width: 12px;
  margin-top: 12px;
}
</style>